Docker MySQL を使ってレプリケーションを試してみた
https://gyazo.com/210836e009fa8b8b531fbcf8e8e6dcf3
こちらの記事を自分で試してみたかったので、やってみました。
今回は MySQL 8 のイメージを使用しました。
また、個人的によく分からなかったところを追記しています。
必要なファイルの準備
master.cnf
Master 用の設定ファイルです。
server-id はユニークな値をふる必要があります。
log-bin にはバイナリログのパスを指定します。本来は /var/lib/mysql 以下などを指定するところですが、そのディレクトリがなくて配置できないようだったので、 bin-log にしています。
code:master.cnf
character-set-server=utf8
collation-server=utf8_general_ci
log-bin=bin-log
server-id=1
ちなみに MySQL 8.0 からはデフォルトでバイナリログ出力がオンなようです。
replica.cnf
リードレプリカ用の設定です。
read-only と relay-log を追加しています。
code:replica.cnf
character-set-server=utf8
collation-server=utf8_general_ci
log-bin=bin-log
server-id=2
read_only=1
super_read_only=1
relay-log=relay-log
relay-log の方ですが、以下のような warning が出ていたので設定しました。
code:log
071118 16:44:10 Warning Neither --relay-log nor --relay-log-index were used; so replication may break when this MySQL server acts as a slave and has his hostname
changed!! Please use '--relay-log=new_slave_hostname-relay-bin' to avoid this problem.
071118 16:44:10 ERROR Failed to open the relay log './old_slave_hostname-relay-bin.003525' (relay_log_pos 22940879)
071118 16:44:10 ERROR Could not find target log during relay log initialization 071118 16:44:10 ERROR Failed to initialize the master info structure read_only をつけておくと、 SUPER 権限を持つユーザー以外は更新不可になりますが、逆にそれを持ってしまうユーザーだと更新可能になってしまいます。
MySQL 5.7 から super_read_only という設定が出て、 root ユーザーでも更新不可にできるようなので、設定しています。
docker-compose.yml
コンテナ 2 つとボリュームを宣言したオーケストレーションファイルを作成します。
code:docker-compose.yml
version: '3'
services:
mysql-master:
container_name: mysql-master
image: mysql:8.0
ports:
- 3306:3306
cap_add:
- SYS_NICE
volumes:
- mysql-data:/var/lib/mysql2
- ./master.cnf:/etc/mysql/conf.d/my.cnf
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: true
TZ: 'Asia/Tokyo'
mysql-replica:
container_name: mysql-replica
image: mysql:8.0
ports:
- 13306:3306
cap_add:
- SYS_NICE
depends_on:
- mysql
tmpfs: /var/lib/mysql
volumes:
- ./replica.cnf:/etc/mysql/conf.d/my.cnf
- ./start-replica.sh:/docker-entrypoint-initdb.d/start-replica.sh
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: true
TZ: 'Asia/Tokyo'
volumes:
mysql-data:
external:
name: mysql-data
この設定を追加したのは、ログに以下の warning があったためです。
code:warning
mbind: Operation not permitted
特に問題はなさそうでしたが、 こちらの記事 を見て追加しました。 tmpfs オプションは、ホストのメモリ上にファイルを保存するようです。
コンテナを停止すれば削除されるようですが、今回はレプリケーションをするので問題はなさそうです。
start-replica.sh
レプリカの方の初期スクリプトです。
やっていることは以下の通りです。
マスター設定をリセットする。
マスターをダンプする。
レプリカを止めてマスターを流し込む。
マスターのバイナリログとポジションを取得し、レプリカの方のマスター設定を変更する。
レプリケーションを開始する。
code:start-replica.sh
while ! mysqladmin ping -h mysql --silent; do
sleep 1
done
mysql -u root -h mysql-master -e "RESET MASTER;"
mysql -u root -h mysql-master -e "FLUSH TABLES WITH READ LOCK;"
mysqldump -u root -h mysql-master --all-databases --master-data --single-transaction --flush-logs --events > /tmp/master_dump.sql
mysql -u root -e "STOP REPLICA;"
mysql -u root < /tmp/master_dump.sql
log_file=mysql -u root -h mysql-master -e "SHOW MASTER STATUS\G" | grep File: | awk '{print $2}'
pos=mysql -u root -h mysql-master -e "SHOW MASTER STATUS\G" | grep Position: | awk '{print $2}'
mysql -u root -e "RESET REPLICA;"
mysql -u root -e "CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='${log_file}', MASTER_LOG_POS=${pos};"
mysql -u root -e "START REPLICA;"
mysql -u root -h mysql-master -e "UNLOCK TABLES;"
起動する
code:bash
$ docker-compose up -d
これで特にエラーが出ずに起動できていれば大丈夫です。
試しにデータを追加してみます。
code:bash
$ mysql -u root -h 127.0.0.1 -e "CREATE DATABASE testdb;"
$ mysql -u root -h 127.0.0.1 -e "CREATE TABLE testdb.test (id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, foo VARCHAR(255) NOT NULL, bar TEXT);"
$ mysql -uroot -h 127.0.0.1 -e "INSERT INTO testsb.test (foo, bar) VALUES ('foo1', 'bar1'), ('foo2', 'bar2'), ('foo3', 'bar3');"
これで、レプリカの方にデータが反映されていれば OK です。
code:bash
$ mysql -uroot -h 127.0.0.1 -P 13306 -e "SELECT * FROM testdb.test;"
レプリカの設定はこちらで確認できます。
code:bash
$ mysql -uroot -h 127.0.0.1 -P 13306 -e "SHOW REPLICA STATUS \G;"
さいごに
はじめにコンテナを起動させたとき、スクリプトが Permission Denied になりました。
どうも、ボリュームのマウント方法が gRPC FUSE になったっぽい原因のようで、オフにしたら実行できました。
とはいえ、 gRPC FUSE はよく分かってないです。。
(FUSE ボリュームシステムに gRPC でやりとりする?)